package com.alibaba.nacos.naming.utils;

import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.naming.core.v2.metadata.ServiceMetadata;
import com.alibaba.nacos.naming.pojo.Subscriber;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class ServiceUtil {

    public static ServiceInfo selectInstancesWithHealthyProtection(ServiceInfo serviceInfo,
                                                                   ServiceMetadata serviceMetadata,
                                                                   boolean healthyOnly,
                                                                   boolean enableOnly,
                                                                   Subscriber subscriber) {
        return selectInstancesWithHealthyProtection(serviceInfo, serviceMetadata, subscriber.getCluster(), healthyOnly, enableOnly, subscriber.getIp());
    }

    public static ServiceInfo selectInstancesWithHealthyProtection(ServiceInfo serviceInfo,
                                                                   ServiceMetadata serviceMetadata,
                                                                   String cluster,
                                                                   boolean healthyOnly,
                                                                   boolean enableOnly,
                                                                   String subscriberIp) {
        InstancesFilter filter = (serviceInfo1, instances, healthyCount) -> {
            if (serviceMetadata == null) {
                return;
            }

            throw new UnsupportedOperationException();
        };


        return doSelectInstances(serviceInfo, cluster, healthyOnly, enableOnly, filter);
    }

    private static ServiceInfo doSelectInstances(ServiceInfo serviceInfo,
                                                 String cluster,
                                                 boolean healthyOnly,
                                                 boolean enableOnly,
                                                 InstancesFilter filter) {
        ServiceInfo result = new ServiceInfo().setName(serviceInfo.getName())
                .setGroupName(serviceInfo.getGroupName())
                .setCacheMillis(serviceInfo.getCacheMillis())
                .setLastRefTime(serviceInfo.getLastRefTime())
                .setClusters(cluster)
                .setReachProtectionThreshold(false);

        Set<String> clusterSets = StringUtils.isNotBlank(cluster) ? Arrays.stream(cluster.split(",")).collect(Collectors.toSet()) : Collections.emptySet();
        List<Instance> allInstances = serviceInfo.getHosts().stream().filter(instance -> checkEnable(enableOnly, instance) && checkCluster(clusterSets, instance)).collect(Collectors.toList());
        List<Instance> filteredInstances = !healthyOnly ? allInstances : allInstances.stream().filter(Instance::isHealthy).collect(Collectors.toList());
        long healthyCount = allInstances.stream().filter(Instance::isHealthy).count();

        result.setHosts(filteredInstances);
        if (filter != null) {
            filter.doFilter(result, allInstances, healthyCount);
        }

        return result;
    }

    private static boolean checkCluster(Set<String> clusterSet,
                                        Instance instance) {
        return clusterSet.isEmpty() || clusterSet.contains(instance.getClusterName());
    }

    private static boolean checkEnable(boolean enableOnly,
                                       Instance instance) {
        return !enableOnly || instance.isEnabled();
    }

    private interface InstancesFilter {
        void doFilter(ServiceInfo serviceInfo,
                      List<Instance> instances,
                      long healthyCount);
    }
}
